package com.newlink.building.activity

import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.media.AudioManager
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.text.TextUtils
import android.util.Log
import android.util.SparseArray
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.media.AudioFocusRequestCompat
import androidx.media.AudioManagerCompat
import androidx.viewpager2.widget.ViewPager2
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.google.android.gms.common.GoogleApiAvailability
import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.messaging.FirebaseMessaging
import com.newlink.building.App
import com.newlink.building.NL_App.Companion.coreContext
import com.newlink.building.R
import com.newlink.building.activities.main.viewmodels.Module_Phone_CallOverlayViewModel
import com.newlink.building.common_base.activities.NL_GuideActivityNL
import com.newlink.building.common_base.base.BaseApplication
import com.newlink.building.common_base.base.NL_BaseMvpActivity
import com.newlink.building.common_base.base.NL_OnActivityCallback
import com.newlink.building.common_base.constant.Base_Constant
import com.newlink.building.common_base.constant.Base_Constant.LOGIN_EXTRA_ACTION_CONFLICT
import com.newlink.building.common_base.constant.Base_Constant.LOGIN_EXTRA_ACTION_MSG_TIMEOUT
import com.newlink.building.common_base.constant.Base_RouterPath
import com.newlink.building.common_base.constant.NL_Key
import com.newlink.building.common_base.event.AlarmNotifyBean
import com.newlink.building.common_base.event.AlarmNotifyHandleBean
import com.newlink.building.common_base.event.Base_QuickRecordEvent
import com.newlink.building.common_base.event.CallMessageBean
import com.newlink.building.common_base.event.CallMessageDataBean
import com.newlink.building.common_base.event.CaptureExitEditEvent
import com.newlink.building.common_base.event.EnterEditEvent
import com.newlink.building.common_base.event.ExitByHttpEvent
import com.newlink.building.common_base.event.ForcedExitEvent
import com.newlink.building.common_base.event.MessageEvent
import com.newlink.building.common_base.event.OpenDoorResultBean
import com.newlink.building.common_base.event.ReadCountActionEvent
import com.newlink.building.common_base.event.RecordReadCountActionEvent
import com.newlink.building.common_base.event.TYPE_APP_BACKGROUND
import com.newlink.building.common_base.event.TYPE_APP_BACK_PRESS
import com.newlink.building.common_base.event.TYPE_APP_EXIT
import com.newlink.building.common_base.event.TYPE_APP_EXIT_FORCE
import com.newlink.building.common_base.event.TYPE_APP_FINISH_FORCE
import com.newlink.building.common_base.event.TYPE_APP_MQTT_CHECK_STATE
import com.newlink.building.common_base.event.TYPE_APP_MQTT_CHECK_STATE_CALLBACK
import com.newlink.building.common_base.event.TYPE_APP_MQTT_NOTIFY_ALARM
import com.newlink.building.common_base.event.TYPE_APP_MQTT_NOTIFY_ALARM_NOTIFY
import com.newlink.building.common_base.event.TYPE_APP_MQTT_NOTIFY_URGENT
import com.newlink.building.common_base.event.TYPE_APP_MQTT_UPDATE_STATE
import com.newlink.building.common_base.event.TYPE_APP_OPEN_DOOR_RESULT
import com.newlink.building.common_base.event.TYPE_APP_OPEN_DOOR_TIMEOUT
import com.newlink.building.common_base.event.TYPE_APP_REORDER_GLOBALPOPOVER_TO_FRONT
import com.newlink.building.common_base.event.TYPE_APP_RESEND_NOTIFY
import com.newlink.building.common_base.event.TYPE_APP_SCREENSHOT_EDIT_OFF
import com.newlink.building.common_base.event.TYPE_APP_SCREENSHOT_EDIT_ON
import com.newlink.building.common_base.event.TYPE_APP_SHOW_LOADING
import com.newlink.building.common_base.event.TYPE_APP_SHOW_MSG
import com.newlink.building.common_base.event.TYPE_APP_SWITCH_FRAGMENT
import com.newlink.building.common_base.event.TYPE_APP_TOGGLE_DRAWER
import com.newlink.building.common_base.event.TYPE_CALL_MESSAGE_UP
import com.newlink.building.common_base.event.TYPE_CAPTURE_ENTER_EDIT_MODE
import com.newlink.building.common_base.event.TYPE_CAPTURE_EXIT_EDIT_MODE
import com.newlink.building.common_base.event.TYPE_POPOVER_CANCEL_ALARM_NOTIFY
import com.newlink.building.common_base.event.TYPE_SECRET_KEY_ADD_CLICKED
import com.newlink.building.common_base.ext.doNext
import com.newlink.building.common_base.ext.showToast
import com.newlink.building.common_base.ext.showToastLong
import com.newlink.building.common_base.http.Base_RetrofitHelper
import com.newlink.building.common_base.model.bean.Base_MqttConnectWrapper
import com.newlink.building.common_base.model.bean.MqttData
import com.newlink.building.common_base.model.bean.UserInfoData
import com.newlink.building.common_base.model.bean.VersionBean
import com.newlink.building.common_base.utils.Base_CommonUtils
import com.newlink.building.common_base.utils.Base_DeviceUtils
import com.newlink.building.common_base.utils.Base_Preference
import com.newlink.building.common_base.utils.Base_VibratorHelper
import com.newlink.building.common_base.utils.DialogUtil
import com.newlink.building.common_base.utils.GooglePlayUtil
import com.newlink.building.common_base.utils.LogHandlerThread
import com.newlink.building.common_base.utils.NLog
import com.newlink.building.common_base.utils.NetWorkUtil
import com.newlink.building.common_base.utils.RomUtils
import com.newlink.building.common_base.utils.ToastUtils
import com.newlink.building.common_base.utils.checkNewAppVersion
import com.newlink.building.common_base.utils.logDebug
import com.newlink.building.common_base.utils.logInfo
import com.newlink.building.databinding.ActivityMainBinding
import com.newlink.building.databinding.DrawerPersonalWrapperBinding
import com.newlink.building.library_rino.ConnectionController
import com.newlink.building.login.ui.Module_Login_ForgetPwdActivityNL
import com.newlink.building.main.adapter.Module_Main_ViewPage2FragmentAdapter
import com.newlink.building.main.fragment.Module_Main_HomeFragment
import com.newlink.building.main.mvp.contract.Module_Main_MainContract
import com.newlink.building.main.mvp.presenter.Module_Main_MainPresenter
import com.newlink.building.main.other.Module_Main_MainConstants.COMMAND_DISCONNECT_MQTT
import com.newlink.building.main.other.Module_Main_MainConstants.COMMAND_UPDATE_LOCALE
import com.newlink.building.main.other.Module_Main_MqttUtils
import com.newlink.building.main.service.MqttV5Service
import com.newlink.building.manager.Module_Phone_VoipController
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationHelper
import com.newlink.building.obfuscation.Module_Obfuscation_ObfuscationInvoker
import com.newlink.building.push.MessageIntentService
import com.newlink.building.record.Module_Record_GlobalPopoverActivityNL
import com.newlink.building.record.fragment.Module_Record_RecordFragment
import com.newlink.building.record.fragment.mEditMode
import com.newlink.building.secret.fragment.Module_Secret_TempSecretFragment
import com.newlink.building.userinfo.Module_UserInfo_BtOpenDoorService2
import com.newlink.building.userinfo.Module_UserInfo_BtOpenDoorService2.Companion.SERVICE_START
import com.newlink.building.userinfo.fragment.Module_UserInfo_PersonalFragment
import com.newlink.building.userinfo.widget.Module_UserInfo_UpdateDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject

/**
 * 主活动界面 - 应用的主要界面，包含底部导航和各个功能模块
 * Created by xiaodong on 2022/7/25.
 */
@Route(path = Base_RouterPath.PATH_HOME)
class NL_MainActivityNL :
    NL_BaseMvpActivity<Module_Main_MainContract.View, Module_Main_MainContract.Presenter>(),
    Module_Main_MainContract.View,
    AudioManager.OnAudioFocusChangeListener {

    private lateinit var audioManager: AudioManager
    private lateinit var request: AudioFocusRequestCompat
    // 旧的底部导航红点提示已移除，现在使用顶部 segment 控制
    // private lateinit var mIvRecordUnread: ImageView
    // private lateinit var mIvMineUnread: ImageView

    // 是否意外重启
    private var isRestarted: Boolean = false
    private var mHomeFragment: Module_Main_HomeFragment? = null
    private var mSecretFragment: Module_Secret_TempSecretFragment? = null
    private var mRecordFragment: Module_Record_RecordFragment? = null
    private var mPersonalFragment: Module_UserInfo_PersonalFragment? = null
    private var mIndex = FRAGMENT_HOME

    // 界面状态控制
    private var isOnResume = false
    private var isMainExit = false
    private var exitTime: Long = 0L
    private var msgDialog: AlertDialog? = null
    private var isCheckedOverPermission = false

    // 从来电推送通知携带的RemoteAid
    private var handlePushCallRemoteAid = ""

    // IOS要求发送ReInvite携带callId参数
    private var handlePushCallId = ""
    private var callPushRemoteAid: String by Base_Preference(Base_Constant.PUSH_CALL_REMOTE_AID, "")
    private var mRecordReadCountActionEvent: RecordReadCountActionEvent? = null
    private var alarmNorifySet = hashSetOf<Long>()

    // 界面绑定和视图模型
    private lateinit var mBinding: ActivityMainBinding
    private lateinit var callOverlayViewModel: Module_Phone_CallOverlayViewModel
    private var mDrawerPersonalFragment: Module_UserInfo_PersonalFragment? = null

    // ViewPager2 相关
    private lateinit var viewPagerAdapter: Module_Main_ViewPage2FragmentAdapter

    // 导航栏视图
    private var currentSegment = 1
    private var isAnimating = false // 动画状态标记

    companion object {
        // Fragment 标识常量
        private const val FRAGMENT_HOME = 0x01
        private const val FRAGMENT_SECRET = 0x02
        private const val FRAGMENT_RECORD = 0x03
        private const val FRAGMENT_PERSONAL = 0x04

        // 界面相关常量
        private const val BOTTOM_INDEX = "bottom_index"
        private const val TAG_HOME = "tag_home"
        private const val TAG_SECRET = "tag_secret"
        private const val TAG_RECORD = "tag_record"
        private const val TAG_PERSONAL = "tag_personal"

        private const val TAG = "fvl"
    }

    override fun attachLayoutRes(): View {
        mBinding = ActivityMainBinding.inflate(layoutInflater)
        return mBinding.root
    }

    override fun createPresenter(): Module_Main_MainPresenter = Module_Main_MainPresenter()

    override fun initData() {
        // 方法进入时混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("MainActivity", "initData")

        NLog.e("[MainActivity] .. initData")
        LogHandlerThread.instance?.initHanderThead()

        // 在关键初始化前添加混淆
        Module_Obfuscation_ObfuscationInvoker.invokeRandom(this.javaClass.simpleName)

        parsePushIntent()

        if (agoraAppId.isNotEmpty()) {
            ConnectionController.getInstance(applicationContext).initRinoSDK(agoraAppId)
            ConnectionController.getInstance(applicationContext).setAgoraAppId(agoraAppId)
        }
        startFvlServices()
        audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
        request =
            AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                .setOnAudioFocusChangeListener(this)
                .build()
        if (!userInfoData.setPwdFlag && userInfoData.userCategory == 2) {
            jumpToFirstSetPassword()
        }
        if (Module_Phone_VoipController.get().isCallingState()) {
            coreContext.inInComingCallOrOutgoingCallActivity = false
            coreContext.inCallActivity = false
        }
    }

    /**
     * 解析推送意图参数
     */
    private fun parsePushIntent() {
        quickJumpFromNotify(intent)
        val callId = intent.getStringExtra("push-callId")
        val from = intent.getStringExtra("push-from")
        val title = intent.getStringExtra("push-title")
        Log.e("[MainActivity]", "parsePushIntent callId:$callId from:$from title:$title")
        if (!callId.isNullOrEmpty() && !from.isNullOrEmpty()) {
            handlePushCallRemoteAid = from
            handlePushCallId = callId
        }
    }

    /**
     * 重新邀请通话消息上报
     */
    private fun reInviteCallMsgUp(remoteAid: String, callId: String = "") {
        Log.e("[MainActivity]", "reInviteCallMsgUp remoteAid:$remoteAid")
        val msgUpEvent = MessageEvent(
            TYPE_CALL_MESSAGE_UP,
            CallMessageBean(
                msgType = "appOnline",
                data = CallMessageDataBean(
                    "",
                    agoraId.toString(),
                    remoteAid,
                    agoraId.toString(),
                    callId
                )
            )
        )
        EventBus.getDefault().post(msgUpEvent)
    }

    override fun start() {
        super.start()
        val extraMap = intent.getStringExtra("extraMap")
        if (!TextUtils.isEmpty(extraMap)) {
            jumpToSecurityPage(extraMap)
        }
    }

    override fun doReConnected() {
        super.doReConnected()
        showLoading()
        NLog.e("[MainActivity] >>> doReConnected")
        MainScope().launch {
            if (isLogin) {
                if (!Base_CommonUtils.isServiceRunning(
                        this@NL_MainActivityNL,
                        MqttV5Service::class.java.name
                    )
                ) {
                    NLog.e("[MainActivity] >>> doReConnected >> start MQTT SERVER")
                    startMqttServer()
                    hideLoading()
                } else {
                    NLog.e("[MainActivity] >>> mqtt status >> ${Module_Main_MqttUtils.isConnect()}")
                    if (Module_Main_MqttUtils.isConnect()) {
                        NLog.e("[MainActivity] >>> mqtt ok")
                        hideLoading()
                    } else {
                        NLog.e("[MainActivity] >>> mqtt service recheck")
                        EventBus.getDefault().post(MessageEvent(TYPE_APP_MQTT_CHECK_STATE, 1))
                    }
                }
            }
        }
    }

    private fun restartMqttService() {

        MainScope().launch {
            Log.e(TAG, "[MainActivity] >>> stopService")
            Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
                stopService(this)
            }
            delay(2500)
            Log.e(TAG, "[MainActivity] >>> startService")
            startMqttServer()
            hideLoading()
        }
    }

    fun isMqttValid(): Boolean {
        if (!Base_CommonUtils.isServiceRunning(this, MqttV5Service::class.java.name)) {
            return false
        }
        return true
    }

    private fun startFvlServices() {
        // 在服务启动前添加混淆
        Module_Obfuscation_ObfuscationHelper.beforeDatabaseOperation("startServices", isLogin)

        if (!isLogin) {
            // 跳转登录前的混淆
            Module_Obfuscation_ObfuscationInvoker.invokeSpecific(5, Base_RouterPath.PATH_LOGIN)

            ARouter.getInstance().build(Base_RouterPath.PATH_LOGIN).navigation()
            finish()
            return
        }

        // 注册SIP账号前的混淆
        Module_Obfuscation_ObfuscationHelper.onMethodEnter("MainActivity", "registerSipAccount")
        registerSipAccount()

        if (NetWorkUtil.isNetworkConnected(this)) {
            Log.e(TAG, "[MainActivity] >>> startFvlServices")
            startMqttServer()
        }
    }

    private fun registerSipAccount() {
//        VoipController.get().registerAccount("808300", "12345", "172.16.1.97 ", "7060", "fanvil.com", "808300")
        val manager = Module_Phone_VoipController.get()
        Log.e(TAG, "[MainActivity] >>> registerSipAccount isAccountExis:${manager.isAccountExis()}")
        if (!manager.isAccountExis()) {
            // 暂时先固定端口号,使用随机端口randomPort每次启动应用都需要更新sip代理端口
            manager.registerAccount(
                username = agoraId.toString(),
                displayName = userInfoData.name,
                port = Base_Constant.NETWORK_LISTEN_PORT.toString()
            )
        } else {
            manager.delete()
            registerSipAccount()
        }
    }

    /**
     * 启动蓝牙开门服务
     */
    private fun startBtServer() {
        if (useBluetooth) {
            Log.e("jake", "BtOpenDoorService == > ${Module_UserInfo_BtOpenDoorService2::class.java.name}")
            if (!Base_CommonUtils.isServiceRunning(this, Module_UserInfo_BtOpenDoorService2::class.java.name)) {
                val serviceIntent = Intent(applicationContext, Module_UserInfo_BtOpenDoorService2::class.java)
                serviceIntent.action = SERVICE_START
                this.startService(serviceIntent)
            }
        }
    }

    private fun stopBtServer() {
        val app = application as App
        NLog.e("app status  = ${app.isAppForeground}")
        if (!app.isAppForeground) {
            Intent(this, Module_UserInfo_BtOpenDoorService2::class.java).apply {
                stopService(this)
            }
        }
    }

    /**
     * 启动MQTT服务
     */
    private fun startMqttServer() {
        if (Base_CommonUtils.isServiceRunning(this, MqttV5Service::class.java.name)) {
            Log.e(TAG, "[MainActivity] mqttservice is running block")
            return
        }
        Log.e(TAG, "[MainActivity] prepare mqttservice info ")
        var mqttData = intent.getSerializableExtra(NL_Key.EXTRA_MQTT) as MqttData?
        if (mqttData == null) {
            mqttData = mqttDataCache
        }
        Log.e(TAG, "[MainActivity] <connectToBackend> mqttDataCache:$mqttDataCache")
        mqttServerUrl = mqttData.url
        mqttUName = mqttData.userName
        mqttUPassword = accessToken
        Log.e(TAG, "[MainActivity] <connectToBackend> isRestarted:$isRestarted  mqttData:$mqttData")
        mPresenter?.connectMqttServer(
            this@NL_MainActivityNL,
            Base_MqttConnectWrapper(mqttServerUrl, mqttUName, mqttUPassword, userId)
        )
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        quickJumpFromNotify(intent)
    }

    private fun quickJumpFromNotify(intent: Intent?) {
        val extraMap = intent?.getStringExtra("extraMap")
        if (!TextUtils.isEmpty(extraMap)) {
            jumpToSecurityPage(extraMap)
            return
        }
        // 通知额外参数。
        var index = intent?.getIntExtra(NL_Key.TAB_INDEX, -1) as Int
        val subIndex = intent?.getIntExtra(NL_Key.SUB_TAB_INDEX, 0) as Int
        Log.e(TAG, "-----Main fragment------ index:$index subIndex:$subIndex")
        if (index != -1) {
            mIndex = index
            // Use ViewPager2 to switch to the specific fragment
            mBinding.viewPager.setCurrentItem(index - 1, false)
            // Update segment selection
            selectSegment(index)
            if (subIndex != 0) {
                lifecycleScope.launch {
                    delay(100)
                    EventBus.getDefault().post(Base_QuickRecordEvent(subIndex))
                }
            }
        }
    }

    private fun jumpToSecurityPage(extraMap: String?) {
        val jsonObj = JSONObject(extraMap)
        // 获取指定键名的值
        val indexStr: String = jsonObj.getString(NL_Key.TAB_INDEX)
        val subIndexStr: String = jsonObj.getString(NL_Key.SUB_TAB_INDEX)
        var index = indexStr.toInt()
        var subIndex = subIndexStr.toInt()
        Log.e(TAG, "jumpSecurity: " + index + "----" + subIndex)
        mIndex = index
        // Switch to the selected page
        selectSegment(index + 1) // index is 0-based in old code, segment is 1-based
        if (subIndex != 0) {
            lifecycleScope.launch {
                delay(100)
                EventBus.getDefault().post(Base_QuickRecordEvent(subIndex))
            }
        }
    }

    /**
     * 恢复状态实例
     */
    override fun initRestoreInstanceState(savedInstanceState: Bundle) {
        isRestarted = true
        mIndex = savedInstanceState.getInt(BOTTOM_INDEX)
        val home = supportFragmentManager.findFragmentByTag(TAG_HOME)
        if (home != null) {
            mHomeFragment = home as Module_Main_HomeFragment
        }
        val secret = supportFragmentManager.findFragmentByTag(TAG_SECRET)
        if (secret != null) {
            mSecretFragment = secret as Module_Secret_TempSecretFragment
        }
        val record = supportFragmentManager.findFragmentByTag(TAG_RECORD)
        if (record != null) {
            mRecordFragment = record as Module_Record_RecordFragment
        }
        val personal = supportFragmentManager.findFragmentByTag(TAG_PERSONAL)
        if (personal != null) {
            mPersonalFragment = personal as Module_UserInfo_PersonalFragment
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt(BOTTOM_INDEX, mIndex)
    }

    override fun initView() {
        super.initView()
        callOverlayViewModel = ViewModelProvider(this)[Module_Phone_CallOverlayViewModel::class.java]

        callOverlayViewModel.displayCallOverlay.observe(this) {
            mBinding.callOverlay.root.visibility = if (it) View.VISIBLE else View.GONE
        }
        mBinding.callOverlay.root.setOnClickListener { coreContext.onCallOverlayClick() }

        // Setup navigation bar
        setupNavigationBar()

        // Remove bottom navigation setup since we're using segment control
        // mBinding.bottomNavigation is no longer used

        initViewPager()
        initDrawer()
        initCallErrorMessage()
        // addRedPoint() - no longer needed for bottom navigation
    }

    /**
     * 设置导航栏
     */
    private fun setupNavigationBar() {
        // 初始化segment控制器
        val segmentControl = mBinding.mainNavigation.segmentControl.root
        val segmentHome = segmentControl.findViewById<LinearLayout>(R.id.segment_home)
        val segmentKeys = segmentControl.findViewById<LinearLayout>(R.id.segment_keys)
        val segmentRecord = segmentControl.findViewById<LinearLayout>(R.id.segment_record)
        val segmentMe = segmentControl.findViewById<LinearLayout>(R.id.segment_me)

        // 设置segment点击监听器
        segmentHome.setOnClickListener {
            selectSegment(1)
        }

        segmentKeys.setOnClickListener {
            selectSegment(2)
        }

        segmentRecord.setOnClickListener {
            selectSegment(3)
        }

        segmentMe.setOnClickListener {
            selectSegment(4)
        }

        // 初始选中 - 无动画初始化首页segment状态
        currentSegment = 0 // 临时设置为0，确保selectSegment(1)能正常执行
        selectSegment(1, animate = false)

        // 设置侧边栏切换按钮
        mBinding.mainNavigation.homeSearchLayout.imgMenu.setOnClickListener {
            openDrawer()
        }
        mBinding.mainNavigation.imgDrawer.setOnClickListener {
            openDrawer()
        }

        // 设置导航栏add按钮点击监听器
        mBinding.mainNavigation.btnAdd.setOnClickListener {
            // 发送EventBus事件到Keys页面
            EventBus.getDefault().post(MessageEvent(TYPE_SECRET_KEY_ADD_CLICKED, null))
        }
    }

    /**
     * 选择segment
     * @param index segment索引
     * @param animate 是否显示动画
     */
    private fun selectSegment(index: Int, animate: Boolean = true) {
        // 防止重复选择或动画进行中时的操作
        if (currentSegment == index || (animate && isAnimating)) {
            return
        }

        if (animate) {
            isAnimating = true
        }
        currentSegment = index

        // 更新ViewPager2
        mBinding.viewPager.setCurrentItem(index - 1, false)

        // 根据segment更新导航栏内容
        if (animate) {
            updateNavigationBarContent(index)
        } else {
            updateNavigationBarContentWithoutAnimation(index)
        }

        // 更新segment视觉状态
        if (animate) {
            updateSegmentVisualState(index)
        } else {
            updateSegmentVisualStateWithoutAnimation(index)
        }

        // 动画完成后重置标记
        if (animate) {
            mBinding.viewPager.postDelayed(
                {
                    isAnimating = false
                },
                400
            ) // 略长于动画时间
        }
    }

    /**
     * 更新导航栏内容
     */
    private fun updateNavigationBarContent(segment: Int) {
        // 动画持续时间
        val animDuration = 300L
        val fadeInAlpha = 1f
        val fadeOutAlpha = 0f

        when (segment) {
            1 -> { // 首页
                animateViewTransition(mBinding.mainNavigation.titleBarLayout, false, animDuration) {
                    animateViewTransition(mBinding.mainNavigation.homeSearchLayout.root, true, animDuration)
                    // 只在MQTT未连接时显示状态提示（status != 2）
                    if (Base_Constant.MQTT_STATUS != 2) {
                        animateViewTransition(mBinding.mainNavigation.mqttStatusLayout.root, true, animDuration)
                    } else {
                        mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.GONE
                    }
                    mBinding.mainNavigation.projectManagementLayout.root.visibility =
                        if (userInfoData.userCategory == 3) View.VISIBLE else View.GONE
                    if (userInfoData.userCategory == 3) {
                        animateViewTransition(mBinding.mainNavigation.projectManagementLayout.root, true, animDuration)
                    }
                    animateViewTransition(mBinding.mainNavigation.navThirdRow, true, animDuration)
                }
                mBinding.mainNavigation.recordMenuLayout.visibility = View.GONE
            }
            2 -> { // 密钥
                animateViewTransition(mBinding.mainNavigation.homeSearchLayout.root, false, animDuration) {
                    animateViewTransition(mBinding.mainNavigation.titleBarLayout, true, animDuration) {
                        mBinding.mainNavigation.tvTitle.text = "Keys"
                        animateViewTransition(mBinding.mainNavigation.btnAdd, true, animDuration)
                    }
                }
                mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.GONE
                mBinding.mainNavigation.recordMenuLayout.visibility = View.GONE
                mBinding.mainNavigation.navThirdRow.visibility = View.GONE
                mBinding.mainNavigation.projectManagementLayout.root.visibility = View.GONE
            }
            3 -> { // 记录
                animateViewTransition(mBinding.mainNavigation.homeSearchLayout.root, false, animDuration) {
                    animateViewTransition(mBinding.mainNavigation.titleBarLayout, true, animDuration) {
                        mBinding.mainNavigation.tvTitle.text = getString(R.string.tab_record)
                    }
                }
                mBinding.mainNavigation.btnAdd.visibility = View.GONE
                mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.GONE
                mBinding.mainNavigation.recordMenuLayout.visibility = View.GONE
                mBinding.mainNavigation.navThirdRow.visibility = View.GONE
                mBinding.mainNavigation.projectManagementLayout.root.visibility = View.GONE
            }
            4 -> { // 个人中心 - 已移至侧边栏
                // 个人页面移至侧边栏，可能不需要此处理
            }
        }
    }

    /**
     * 更新导航栏内容（无动画版本）
     */
    private fun updateNavigationBarContentWithoutAnimation(segment: Int) {
        when (segment) {
            1 -> { // 首页
                mBinding.mainNavigation.homeSearchLayout.root.visibility = View.VISIBLE
                mBinding.mainNavigation.titleBarLayout.visibility = View.GONE
                // 只在MQTT未连接时显示状态提示（status != 2）
                mBinding.mainNavigation.mqttStatusLayout.root.visibility =
                    if (Base_Constant.MQTT_STATUS != 2) View.VISIBLE else View.GONE
                mBinding.mainNavigation.recordMenuLayout.visibility = View.GONE
                mBinding.mainNavigation.projectManagementLayout.root.visibility =
                    if (userInfoData.userCategory == 3) View.VISIBLE else View.GONE
                mBinding.mainNavigation.navThirdRow.visibility = View.VISIBLE
            }
            2 -> { // 密钥
                mBinding.mainNavigation.homeSearchLayout.root.visibility = View.GONE
                mBinding.mainNavigation.titleBarLayout.visibility = View.VISIBLE
                mBinding.mainNavigation.tvTitle.text = "Keys"
                mBinding.mainNavigation.btnAdd.visibility = View.VISIBLE
                mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.GONE
                mBinding.mainNavigation.recordMenuLayout.visibility = View.GONE
                mBinding.mainNavigation.navThirdRow.visibility = View.GONE
                mBinding.mainNavigation.projectManagementLayout.root.visibility = View.GONE
            }
            3 -> { // 记录
                mBinding.mainNavigation.homeSearchLayout.root.visibility = View.GONE
                mBinding.mainNavigation.titleBarLayout.visibility = View.VISIBLE
                mBinding.mainNavigation.tvTitle.text = getString(R.string.tab_record)
                mBinding.mainNavigation.btnAdd.visibility = View.GONE
                mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.GONE
                mBinding.mainNavigation.recordMenuLayout.visibility = View.GONE
                mBinding.mainNavigation.navThirdRow.visibility = View.GONE
                mBinding.mainNavigation.projectManagementLayout.root.visibility = View.GONE
            }
            4 -> { // 个人中心 - 已移至侧边栏
                // 个人页面移至侧边栏，可能不需要此处理
            }
        }
    }

    /**
     * 视图切换动画
     * @param view 要动画的视图
     * @param show 是否显示
     * @param duration 动画持续时间
     * @param onComplete 动画完成回调
     */
    private fun animateViewTransition(
        view: View,
        show: Boolean,
        duration: Long,
        onComplete: (() -> Unit)? = null
    ) {
        if (show) {
            // 显示动画：淡入 + 轻微向上滑动
            view.visibility = View.VISIBLE
            view.alpha = 0f
            view.translationY = 20f
            view.animate()
                .alpha(1f)
                .translationY(0f)
                .setDuration(duration)
                .withEndAction { onComplete?.invoke() }
                .start()
        } else {
            // 隐藏动画：淡出 + 轻微向下滑动
            view.animate()
                .alpha(0f)
                .translationY(-20f)
                .setDuration(duration)
                .withEndAction {
                    view.visibility = View.GONE
                    view.translationY = 0f
                    onComplete?.invoke()
                }
                .start()
        }
    }

    /**
     * 更新segment视觉状态
     */
    private fun updateSegmentVisualState(index: Int) {
        val segmentControl = mBinding.mainNavigation.segmentControl.root
        val segmentHome = segmentControl.findViewById<LinearLayout>(R.id.segment_home)
        val segmentKeys = segmentControl.findViewById<LinearLayout>(R.id.segment_keys)
        val segmentRecord = segmentControl.findViewById<LinearLayout>(R.id.segment_record)
        val segmentMe = segmentControl.findViewById<LinearLayout>(R.id.segment_me)

        val textHome = segmentControl.findViewById<TextView>(R.id.text_home)
        val textKeys = segmentControl.findViewById<TextView>(R.id.text_keys)
        val textRecord = segmentControl.findViewById<TextView>(R.id.text_record)
        val textMe = segmentControl.findViewById<TextView>(R.id.text_me)

        val iconHome = segmentControl.findViewById<ImageView>(R.id.icon_home)
        val iconKeys = segmentControl.findViewById<ImageView>(R.id.icon_keys)
        val iconRecord = segmentControl.findViewById<ImageView>(R.id.icon_record)
        val iconMe = segmentControl.findViewById<ImageView>(R.id.icon_me)

        // 重置所有segments
        segmentHome.setBackgroundResource(android.R.color.transparent)
        segmentKeys.setBackgroundResource(android.R.color.transparent)
        segmentRecord.setBackgroundResource(android.R.color.transparent)
        segmentMe.setBackgroundResource(android.R.color.transparent)

        textHome.setTextColor(resources.getColor(R.color.grey600))
        textKeys.setTextColor(resources.getColor(R.color.grey600))
        textRecord.setTextColor(resources.getColor(R.color.grey600))
        textMe.setTextColor(resources.getColor(R.color.grey600))

        // 重置容器和图标状态
        segmentHome.isSelected = false
        segmentKeys.isSelected = false
        segmentRecord.isSelected = false
        segmentMe.isSelected = false
        iconHome.isSelected = false
        iconKeys.isSelected = false
        iconRecord.isSelected = false
        iconMe.isSelected = false

        // 设置选中的segment，添加动画效果
        val animDuration = 200L
        when (index) {
            1 -> {
                animateSegmentSelection(segmentHome, textHome, iconHome, animDuration)
            }
            2 -> {
                animateSegmentSelection(segmentKeys, textKeys, iconKeys, animDuration)
            }
            3 -> {
                animateSegmentSelection(segmentRecord, textRecord, iconRecord, animDuration)
            }
            4 -> {
                animateSegmentSelection(segmentMe, textMe, iconMe, animDuration)
            }
        }
    }

    /**
     * Segment选择动画
     * @param container segment容器
     * @param textView 文本视图
     * @param iconView 图标视图
     * @param duration 动画持续时间
     */
    private fun animateSegmentSelection(
        container: LinearLayout,
        textView: TextView,
        iconView: ImageView,
        duration: Long
    ) {
        // 背景动画
        container.setBackgroundResource(R.drawable.bg_segment_selected)
        container.isSelected = true
        container.animate()
            .scaleX(1.05f)
            .scaleY(1.05f)
            .setDuration(duration / 2)
            .withEndAction {
                container.animate()
                    .scaleX(1f)
                    .scaleY(1f)
                    .setDuration(duration / 2)
                    .start()
            }
            .start()

        // 文本颜色动画
        textView.setTextColor(resources.getColor(R.color.white))

        // 图标状态动画
        iconView.isSelected = true
        iconView.animate()
            .scaleX(1.1f)
            .scaleY(1.1f)
            .setDuration(duration / 2)
            .withEndAction {
                iconView.animate()
                    .scaleX(1f)
                    .scaleY(1f)
                    .setDuration(duration / 2)
                    .start()
            }
            .start()
    }

    /**
     * 更新segment视觉状态（无动画版本）
     */
    private fun updateSegmentVisualStateWithoutAnimation(index: Int) {
        val segmentControl = mBinding.mainNavigation.segmentControl.root
        val segmentHome = segmentControl.findViewById<LinearLayout>(R.id.segment_home)
        val segmentKeys = segmentControl.findViewById<LinearLayout>(R.id.segment_keys)
        val segmentRecord = segmentControl.findViewById<LinearLayout>(R.id.segment_record)
        val segmentMe = segmentControl.findViewById<LinearLayout>(R.id.segment_me)

        val textHome = segmentControl.findViewById<TextView>(R.id.text_home)
        val textKeys = segmentControl.findViewById<TextView>(R.id.text_keys)
        val textRecord = segmentControl.findViewById<TextView>(R.id.text_record)
        val textMe = segmentControl.findViewById<TextView>(R.id.text_me)

        val iconHome = segmentControl.findViewById<ImageView>(R.id.icon_home)
        val iconKeys = segmentControl.findViewById<ImageView>(R.id.icon_keys)
        val iconRecord = segmentControl.findViewById<ImageView>(R.id.icon_record)
        val iconMe = segmentControl.findViewById<ImageView>(R.id.icon_me)

        // 重置所有segments
        segmentHome.setBackgroundResource(android.R.color.transparent)
        segmentKeys.setBackgroundResource(android.R.color.transparent)
        segmentRecord.setBackgroundResource(android.R.color.transparent)
        segmentMe.setBackgroundResource(android.R.color.transparent)

        textHome.setTextColor(resources.getColor(R.color.grey600))
        textKeys.setTextColor(resources.getColor(R.color.grey600))
        textRecord.setTextColor(resources.getColor(R.color.grey600))
        textMe.setTextColor(resources.getColor(R.color.grey600))

        // 重置容器和图标状态
        segmentHome.isSelected = false
        segmentKeys.isSelected = false
        segmentRecord.isSelected = false
        segmentMe.isSelected = false
        iconHome.isSelected = false
        iconKeys.isSelected = false
        iconRecord.isSelected = false
        iconMe.isSelected = false

        // 设置选中的segment（无动画）
        when (index) {
            1 -> {
                segmentHome.setBackgroundResource(R.drawable.bg_segment_selected)
                segmentHome.isSelected = true
                textHome.setTextColor(resources.getColor(R.color.white))
                iconHome.isSelected = true
            }
            2 -> {
                segmentKeys.setBackgroundResource(R.drawable.bg_segment_selected)
                segmentKeys.isSelected = true
                textKeys.setTextColor(resources.getColor(R.color.white))
                iconKeys.isSelected = true
            }
            3 -> {
                segmentRecord.setBackgroundResource(R.drawable.bg_segment_selected)
                segmentRecord.isSelected = true
                textRecord.setTextColor(resources.getColor(R.color.white))
                iconRecord.isSelected = true
            }
            4 -> {
                segmentMe.setBackgroundResource(R.drawable.bg_segment_selected)
                segmentMe.isSelected = true
                textMe.setTextColor(resources.getColor(R.color.white))
                iconMe.isSelected = true
            }
        }
    }

    /**
     * 初始化侧边栏
     */
    private fun initDrawer() {
        // 让侧边栏扩展到状态栏下方
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)

        // 设置侧边栏扩展到状态栏下方
        mBinding.drawerLayout.setStatusBarBackgroundColor(android.graphics.Color.TRANSPARENT)
        mBinding.drawerLayout.systemUiVisibility =
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

        // 动态设置状态栏高度
        val statusBarHeight = getStatusBarHeight()
        // 通过 include 的 binding 访问子布局中的 view
        val drawerBinding = DrawerPersonalWrapperBinding.bind(mBinding.drawerLayoutWrapper.root)
        drawerBinding.statusBarBackground.layoutParams?.height = statusBarHeight
        drawerBinding.statusBarBackground.requestLayout()

        // 初始化侧边栏个人信息Fragment
        if (mDrawerPersonalFragment == null) {
            mDrawerPersonalFragment = Module_UserInfo_PersonalFragment.getInstance()
            val transaction = supportFragmentManager.beginTransaction()
            transaction.add(drawerBinding.drawerFragmentContent.id, mDrawerPersonalFragment!!)
            transaction.commit()
        }

        // 设置侧边栏监听器
        mBinding.drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
            override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
            override fun onDrawerOpened(drawerView: View) {}
            override fun onDrawerClosed(drawerView: View) {}
            override fun onDrawerStateChanged(newState: Int) {}
        })
    }

    /**
     * 获取状态栏高度
     */
    private fun getStatusBarHeight(): Int {
        var result = 0
        val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")

        if (resourceId > 0) {
            result = resources.getDimensionPixelSize(resourceId)
        }
        return result
    }

    /**
     * 打开侧边栏
     */
    fun openDrawer() {
        mBinding.drawerLayout.openDrawer(GravityCompat.START)
    }

    /**
     * 关闭侧边栏
     */
    fun closeDrawer() {
        if (mBinding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
            mBinding.drawerLayout.closeDrawer(GravityCompat.START)
        }
    }

    /**
     * 初始化ViewPager
     */
    private fun initViewPager() {
        // 初始化ViewPager2的fragments
        val fragments = SparseArray<Fragment>()

        // 使用现有的HomeFragment (包含搜索栏 + segment控制器 + 设备列表)
        if (mHomeFragment == null) {
            mHomeFragment = Module_Main_HomeFragment.getInstance()
        }
        fragments.put(0, mHomeFragment!!)

        // 添加其他fragments
        if (mSecretFragment == null) {
            mSecretFragment = Module_Secret_TempSecretFragment.getInstance()
        }
        fragments.put(1, mSecretFragment!!)

        if (mRecordFragment == null) {
            mRecordFragment = Module_Record_RecordFragment.getInstance(mRecordReadCountActionEvent)
        }
        fragments.put(2, mRecordFragment!!)

//        if (mPersonalFragment == null) {
//            mPersonalFragment = PersonalFragment.getInstance()
//        }
//        fragments.put(3, mPersonalFragment!!)

        // 设置ViewPager2适配器
        viewPagerAdapter = Module_Main_ViewPage2FragmentAdapter(this, fragments)
        mBinding.viewPager.adapter = viewPagerAdapter
        mBinding.viewPager.offscreenPageLimit = 4

        // 设置初始页面为首页 (索引0)
        mBinding.viewPager.setCurrentItem(0, false)

        // 添加页面切换监听器，与segment控制器同步
        mBinding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            private var lastPosition = -1

            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)
                // 只在位置真正改变时才更新，避免重复动画
                if (position != lastPosition) {
                    lastPosition = position
                    // 根据页面变化更新segment选择
                    selectSegment(position + 1)
                }
            }

            override fun onPageScrollStateChanged(state: Int) {
                super.onPageScrollStateChanged(state)
                // 当开始滑动时，可以添加一些预备动画效果
                when (state) {
                    ViewPager2.SCROLL_STATE_DRAGGING -> {
                        // 用户开始滑动，可以在这里添加准备动画
                    }
                    ViewPager2.SCROLL_STATE_SETTLING -> {
                        // 滑动正在结算到最终位置
                    }
                    ViewPager2.SCROLL_STATE_IDLE -> {
                        // 滑动结束，已到达最终位置
                    }
                }
            }
        })
    }

    /**
     * 初始化通话错误消息
     */
    private fun initCallErrorMessage() {
        coreContext.callErrorMessageResourceId.observe(
            this
        ) {
            it.consume { message ->
                showSnackBar(message)
            }
        }
    }

    override fun showSnackBar(message: String) {
        Snackbar.make(mBinding.viewPager, message, Snackbar.LENGTH_LONG).show()
    }

    override fun onAudioFocusChange(focusChange: Int) {
        logDebug<NL_MainActivityNL>("[MainActivity] onAudioFocusChange $focusChange")
        // Call.State.Paused时Hold通话,其它通话结束时恢复通话
        if (focusChange == AudioManager.AUDIOFOCUS_GAIN ||
            focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT ||
            focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE ||
            focusChange == AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
        ) {
            logDebug<NL_MainActivityNL>("onAudioFocusChange")
        }
    }

    override fun onResume() {
        super.onResume()
        NLog.e("[MainActivity] >>> onResume")
        isOnResume = true

        startBtServer()
        checkMqttState()
        if (callOverlayViewModel.displayCallOverlay.value == true) {
            coreContext.onCallOverlayClick()
        }

//        showUpdateDialog(VersionBean(true, "28", "1.1.10", ""))

        checkNewAppVersion(accessToken) { versionBean ->
            if (versionBean != null) {
                if (versionBean.versionCode.isNotEmpty()) {
                    if (versionBean.versionCode.toInt() > Base_DeviceUtils.getAppVersion(this)) {
                        if (versionBean.forceUpdate) {
                            showUpdateDialog(versionBean)
                            return@checkNewAppVersion
                        }
                    }
                }
            }

//            if (!isCheckedOverPermission) {
//                checkOverlayPermission()
//                isCheckedOverPermission = true
//            }
            MainScope().launch {
                delay(300)
                if (isFirstUse) {
                    val guideIntent = Intent(this@NL_MainActivityNL, NL_GuideActivityNL::class.java)
                    startActivity(guideIntent)
                }
            }
        }

        updateToken()
    }

    private fun checkMqttState() {
        MainScope().launch {
            doReConnected()
        }
    }

    private fun updateToken() {
        if (System.currentTimeMillis() - tokenStart > Base_Constant.TOKEN_VALID_TIME) {
            NLog.e("------------update token start.---------")
            Base_RetrofitHelper.service.updateToken(accessToken).doNext {
                if (it.code == 200) {
                    NLog.e("------------update token success---------")
                    tokenStart = System.currentTimeMillis()
                } else {
                    NLog.e("------------update token failed---------")
                }
            }
        }
    }

    private fun checkOverlayPermission() {
        if (Settings.canDrawOverlays(this)) {
            Log.e(TAG, "------------a.have overlay permission---------")
            if (RomUtils.isBackgroundStartAllowed(this)) {
                Log.e(TAG, "------------popup window permission---------")
                lifecycleScope.launch(Dispatchers.Main) {
                    if (RomUtils.isHuawei()) {
                        delay(1000)
                        ToastUtils.showTextToast(getString(R.string.huawei_over_warning))
                    } else {
                        checkDeviceCompatibility()
                    }
                }
            }
        } else {
            Log.e(TAG, "------------b.not have overlay permission---------")
            val builder = DialogUtil.getMessageNewDialog(
                this@NL_MainActivityNL,
                getString(R.string.app_need_allow_display_over),
                getString(R.string.app_need_allow_display_over_go),
                object : DialogInterface.OnClickListener {
                    override fun onClick(dialog: DialogInterface?, which: Int) {
                        requestOverlayPermission()
                    }
                },
                getString(R.string.app_need_allow_display_over_know),
                object : DialogInterface.OnClickListener {
                    override fun onClick(dialog: DialogInterface?, which: Int) {
                        msgDialog?.dismiss()
                    }
                }
            )

            msgDialog = builder.create()
            // T84019 修改Unable to add window
            if (!isFinishing) {
                msgDialog?.show()
            }
            msgDialog?.window?.run {
                attributes = attributes.apply {
                    width = (windowManager.defaultDisplay.width * 0.95).toInt()
                    gravity = Gravity.CENTER
                }
            }
        }
    }

    private fun requestOverlayPermission() {
        val intent =
            Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName"))
        startActivityForResult(
            intent,
            object : NL_OnActivityCallback {
                override fun onActivityResult(resultCode: Int, data: Intent?) {
                    Log.e(TAG, "[MainActivity]--- onActivityResult--- $resultCode")
                    lifecycleScope.launch {
                        delay(1000)
                        withContext(Dispatchers.Main) {
                            if (Settings.canDrawOverlays(this@NL_MainActivityNL)) {
                                Log.e(TAG, "[MainActivity]---set overlay permission success--- ")
                                if (RomUtils.isHuawei()) {
//                                    ToastUtils.showTextToast(this@MainActivity, getString(R.string.huawei_over_warning), Toast.LENGTH_LONG)
                                    showToastLong(getString(R.string.huawei_over_warning))
                                } else {
                                    checkDeviceCompatibility()
                                }
                            } else {
                                Log.e(TAG, "[MainActivity]---set overlay permission failed--- ")
                            }
                            startFvlServices()
                        }
                    }
                }
            }
        )
    }

    private suspend fun checkDeviceCompatibility() {
        val specialDeviceState = RomUtils.isBackgroundStartAllowed(this@NL_MainActivityNL)

        Log.e(TAG, "[MainActivity]---  over other app: --- $specialDeviceState")
        if (!specialDeviceState) {
            if (RomUtils.isVivo()) {
                ToastUtils.showTextToastLong(getString(R.string.over_app_permission_vivo_tips))
                delay(1000)
                RomUtils.requestVivoBgStartPermission(this@NL_MainActivityNL, 1005)
            } else if (RomUtils.isXiaoMi()) {
                ToastUtils.showTextToastLong(getString(R.string.over_app_permission_vivo_xiaomi))
                delay(1000)
                RomUtils.requestXiaomiBgStartPermission(this@NL_MainActivityNL, 1006)
            }
        }
    }

    override fun onPause() {
        super.onPause()
        isOnResume = false
        NLog.e("[MainActivity]  = onPause")
    }

    override fun onStop() {
        super.onStop()
        NLog.e("[MainActivity]  = onStop")
//        stopBtServer()
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        NLog.e("[MainActivity] onWindowFocusChanged = $hasFocus")
    }

    override fun tokenAvailable() {
        startFvlServices()
    }

    /**
     * Http 点击登出button 后, 收到登出结果
     * @param success Boolean
     * @param reason Int
     */
    override fun showLogoutSuccess(success: Boolean, reason: Int) {
        if (success) {
            // Stop Mqtt
            Log.e(
                TAG,
                "[MainActivity]  MqttV5Service from ${javaClass.simpleName} <showLogoutSuccess>"
            )
            Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
                stopService(this)
            }
            // Stop SIP
            isLogin = false

            lastBleAddr = ""
            // Jump to Login
            if (reason == 1) {
                ARouter.getInstance().build(Base_RouterPath.PATH_LOGIN)
                    .withFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
                    .withAction(LOGIN_EXTRA_ACTION_CONFLICT)
                    .navigation()
            } else {
                ARouter.getInstance().build(Base_RouterPath.PATH_LOGIN)
                    .withFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
                    .withAction(LOGIN_EXTRA_ACTION_MSG_TIMEOUT)
                    .navigation()
            }

            // finish self
            finish()
        }
    }

    override fun showUserInfo(userInfo: UserInfoData) {
        userInfoData = userInfo
        // 通过getUserInfo 的方法,首先确认Token是否可用
        if (NetWorkUtil.isNetworkConnected(this)) {
            Log.e(TAG, "[MainActivity] >>> showUserInfo")
            startMqttServer()
        }
//        if (userInfo.readCount > 0) {
//            iv_unread.visibility = View.VISIBLE
//        } else {
//            iv_unread.visibility = View.GONE
//        }
    }

    private fun initGoogleServiceFCM() {
        val makeGooglePlayServicesAvailable =
            GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(this)
        makeGooglePlayServicesAvailable.addOnCompleteListener {
            val isSuccessful = it?.isSuccessful
            val exception = it?.exception
            logDebug<NL_MainActivityNL>("[MainActivity] isSuccessful:$isSuccessful")
            logDebug<NL_MainActivityNL>("[MainActivity] exception:$exception")
        }

        /*检索当前注册令牌*/
        FirebaseMessaging.getInstance().token.addOnCompleteListener(
            OnCompleteListener { task ->
                var mFCMToken: String by Base_Preference(Base_Constant.FCM_TOKEN, "")

                if (!task.isSuccessful) {
                    // 获取新的FCM注册令牌失败
                    logDebug<NL_MainActivityNL>("获取新的FCM注册令牌失败：$mFCMToken")
                } else {
                    // 获取新的注册令牌成功
                    val token = task.result
                    mFCMToken = token
                    logDebug<NL_MainActivityNL>("获取新的FCM注册令牌成功：$mFCMToken")
                }
            }
        )
    }

    override fun recreate() {
        try {
            val fragmentTransaction = supportFragmentManager.beginTransaction()
            if (mHomeFragment != null) {
                fragmentTransaction.remove(mHomeFragment!!)
            }
            if (mSecretFragment != null) {
                fragmentTransaction.remove(mSecretFragment!!)
            }
            if (mRecordFragment != null) {
                fragmentTransaction.remove(mRecordFragment!!)
            }
            if (mPersonalFragment != null) {
                fragmentTransaction.remove(mPersonalFragment!!)
            }
            fragmentTransaction.commitAllowingStateLoss()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        super.recreate()
    }

    override fun onBackPressed() {
        if (mBinding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
            mBinding.drawerLayout.closeDrawer(GravityCompat.START)
            return
        }
        if (mEditMode) {
            EventBus.getDefault().post(MessageEvent(TYPE_APP_BACK_PRESS, 0))
            return
        }
        if (System.currentTimeMillis() - exitTime > 2000) {
            showToast(getString(R.string.press_exit_app))
            exitTime = System.currentTimeMillis()
        } else {
            finish()
            isMainExit = true
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        NLog.e("[MainActivity]  onDestroy")
        mHomeFragment = null
        mSecretFragment = null
        mRecordFragment = null
        mPersonalFragment = null

        Base_Constant.MQTT_STATUS = 4

        Log.e(TAG, "[MainActivity]  stop  MqttV5Service !!!!!!!!!!! ")
        Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
            stopService(this)
        }
        Log.e(TAG, "[MainActivity]  stop BtService !!!!!!!!!!! ")
        Intent(applicationContext, Module_UserInfo_BtOpenDoorService2::class.java).apply {
            stopService(this)
        }

        LogHandlerThread.instance?.quit()
        ConnectionController.getInstance(applicationContext).destroy()

        AudioManagerCompat.abandonAudioFocusRequest(audioManager, request)
        Module_Phone_VoipController.get().delete()
        Base_VibratorHelper.getInstance(applicationContext).clear()
        if (isMainExit) {
            isMainExit = false
//            android.os.Process.killProcess(android.os.Process.myPid())
//            exitProcess(0)
        }
    }

    private fun forceStopApplication() {

        Log.e(TAG, "[MainActivity]  收到退出: onForcedExitEvent")

        // Stop Mqtt
        Log.e(
            TAG,
            "[MainActivity]  操作 MqttV5Service from ${javaClass.simpleName} <forceStopApplication>"
        )
        Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
            action = COMMAND_DISCONNECT_MQTT
            stopService(this)
        }
        Log.e(TAG, "[MainActivity]  操作 BtService ")
        Intent(applicationContext, Module_UserInfo_BtOpenDoorService2::class.java).apply {
            stopService(this)
        }
        useBluetooth = false

        setReceivePush(false)
        Module_Phone_VoipController.get().delete()
        isLogin = false
        lastBleAddr = ""
        // Jump to Login
        ARouter.getInstance().build(Base_RouterPath.PATH_LOGIN)
            .withFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            .navigation()
        // finish self
        finish()
    }

    private fun setReceivePush(b: Boolean) {
        val app = application as App
        NLog.e("[PushService] ★★★★★★ setReceivePush: $b ★★★★★★")
        if (b) {
            app.login()
        } else {
            app.logout()
        }
    }

    // ----------------Event Bus Calling---------------------------
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMsgReceived(event: MessageEvent) {
        when (event.msgType) {

            TYPE_CAPTURE_ENTER_EDIT_MODE -> {
                // Hide navigation if needed during edit mode
                mBinding.mainNavigation.root.visibility = View.GONE
            }

            TYPE_CAPTURE_EXIT_EDIT_MODE -> {
                // Show navigation when exiting edit mode
                mBinding.mainNavigation.root.visibility = View.VISIBLE
            }

            TYPE_APP_OPEN_DOOR_TIMEOUT -> {
                val msgId = event.msgContent as String
                onOpenDoorTimeout(msgId)
            }

            TYPE_APP_OPEN_DOOR_RESULT -> {
                logInfo<NL_MainActivityNL>("onOpenDoorResult")
                val event = event.msgContent as OpenDoorResultBean
                showOpenDoorResultDialog(event)
            }

            TYPE_APP_SCREENSHOT_EDIT_ON -> mBinding.mainNavigation.root.visibility = View.GONE
            TYPE_APP_SCREENSHOT_EDIT_OFF -> mBinding.mainNavigation.root.visibility = View.VISIBLE
            TYPE_APP_EXIT -> {
                Log.e(TAG, "[MainActivity] >>> MainActivity App Exit")
                val isExit = event.msgContent as Boolean
                if (!isExit) {
                    return
                }
                Log.e(
                    TAG,
                    "[MainActivity] >>> stop MqttV5Service from " +
                        "${javaClass.simpleName} <TYPE_APP_EXIT>"
                )
                Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
                    stopService(this)
                }

                useBluetooth = false

//                Intent(applicationContext, BtOpenDoorService::class.java).apply {
                Intent(applicationContext, Module_UserInfo_BtOpenDoorService2::class.java).apply {
                    stopService(this)
                }
            }

            TYPE_APP_EXIT_FORCE -> forceStopApplication()

            TYPE_APP_MQTT_NOTIFY_URGENT -> {
            }

            TYPE_APP_FINISH_FORCE -> {
                isMainExit = true
                finish()
            }

            TYPE_APP_MQTT_NOTIFY_ALARM -> {
                val alarmBean = event.msgContent as AlarmNotifyBean
                Log.e(TAG, "[MainActivity] >>> alarm : session id is $alarmBean")
                onAlarmActionEvent(alarmBean)
            }

            TYPE_APP_SHOW_MSG -> {
                val msgBean = event.msgContent as String
                showToast(msgBean)
            }

            TYPE_APP_SHOW_LOADING -> {
                val isShow = event.msgContent as Boolean
                if (isShow) {
                    showLoading()
                } else {
                    hideLoading()
                }
            }

            TYPE_APP_MQTT_UPDATE_STATE -> {
                Base_Constant.MQTT_STATUS = event.msgContent as Int
                NLog.e("[MainActivity] >>>  更新MQTT 状态...${Base_Constant.MQTT_STATUS} handlePushCallRemoteAid:$handlePushCallRemoteAid callPushRemoteAid:$callPushRemoteAid")

                // 更新MQTT状态显示：status == 2 表示已连接，其他状态表示未连接
                if (Base_Constant.MQTT_STATUS == 2) {
                    // MQTT已连接，隐藏"未连接到服务器"提示
                    mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.GONE
                    NLog.e("[MainActivity] >>> MQTT已连接，隐藏状态提示")
                } else {
                    // MQTT未连接，只在首页(segment 1)显示"未连接到服务器"提示
                    if (currentSegment == 1) {
                        mBinding.mainNavigation.mqttStatusLayout.root.visibility = View.VISIBLE
                        NLog.e("[MainActivity] >>> MQTT未连接(状态=${Base_Constant.MQTT_STATUS})，显示状态提示")
                    }
                }

                // 从通知点击推送通知
                hideLoading()

                if (event.msgContent == 2 && handlePushCallRemoteAid.isNotEmpty()) {
                    // 取消推送的来电通知
                    val service = Intent(this, MessageIntentService::class.java).apply {
                        action = Base_Constant.ACTION_CANCEL_PUSH_CALL_NOTIFICATION
                    }
                    startService(service)
                    reInviteCallMsgUp(handlePushCallRemoteAid, handlePushCallId)
                    handlePushCallRemoteAid = ""
                    callPushRemoteAid = ""
                    handlePushCallId = ""
                }

                // 没有从推送通知里进入
                if (event.msgContent == 2 && callPushRemoteAid.isNotEmpty()) {
                    // 取消推送的来电通知
                    val service = Intent(this, MessageIntentService::class.java).apply {
                        action = Base_Constant.ACTION_CANCEL_PUSH_CALL_NOTIFICATION
                    }
                    startService(service)
                    reInviteCallMsgUp(callPushRemoteAid, handlePushCallId)
                    handlePushCallRemoteAid = ""
                    callPushRemoteAid = ""
                    handlePushCallId = ""
                }
            }

            TYPE_APP_RESEND_NOTIFY -> {
                NLog.e("[MainActivity] >>>  MQTT RESEND NOTIFY")
                coreContext.notificationsManager.resendForegroundNotification()
                Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
                    action = COMMAND_UPDATE_LOCALE
                    startService(this)
                }
            }

            TYPE_APP_BACKGROUND -> {
                val isBackground = event.msgContent as Boolean
                NLog.e("[MainActivity] >>>  check app status : $isBackground")
                if (isBackground) {
                    // 停止 Mqtt
                    stopBtServer()
                } else {
                    startBtServer()
                }
            }

            TYPE_APP_MQTT_CHECK_STATE_CALLBACK -> {
                val msgContent = event.msgContent as Int
                if (msgContent == 0) {
                    NLog.e("[MainActivity] >>>  !!!!!!!!!!! [reconnect] !!!!!!!!!!")
                    restartMqttService()
                } else {
                    NLog.e("[MainActivity] >>>  !!!!!!!!!!! [auto reconnect] !!!!!!!!!!")
                    hideLoading()
                }
            }

            TYPE_APP_REORDER_GLOBALPOPOVER_TO_FRONT -> {
                NLog.e("[MainActivity] >>>  TYPE_APP_REORDER_GLOBALPOPOVER_FRONT")
                Module_Record_GlobalPopoverActivityNL.startSelfFront(this)
            }

            TYPE_APP_TOGGLE_DRAWER -> {
                val shouldOpen = event.msgContent as Boolean
                if (shouldOpen) {
                    openDrawer()
                } else {
                    closeDrawer()
                }
            }

            TYPE_APP_SWITCH_FRAGMENT -> {
                val fragmentIndex = event.msgContent as Int
                when (fragmentIndex) {
                    1 -> mBinding.viewPager.setCurrentItem(0, true) // Home content
                    2 -> mBinding.viewPager.setCurrentItem(1, true) // Secret
                    3 -> mBinding.viewPager.setCurrentItem(2, true) // Record
                    4 -> mBinding.viewPager.setCurrentItem(3, true) // Personal
                }
            }
        }
    }

    private fun onAlarmActionEvent(alarmNotifyBean: AlarmNotifyBean) {
        val alarmBean = alarmNotifyBean.data
        Log.e(TAG, "[MainActivity] => [${packageName.javaClass.name}] 安防通知 : $alarmBean")
        if (alarmBean.handle == 0) {
            alarmNorifySet.add(alarmBean.id)

//             通知采用推送的方式来展示 本地的先不用了
//            NotificationHandler(this@MainActivity)
//                .displayAlarmKcpNotification(alarmBean)
        }

        if (GooglePlayUtil.onCheckGooglePlayServices(this) && Settings.canDrawOverlays(this)) {
            Module_Record_GlobalPopoverActivityNL.startSelf(
                this,
                alarmBean,
                fromRecord = alarmNotifyBean.fromRecord
            )
            return
        }

        if (!(application as BaseApplication).isAppForeground) {
            val alarmTitle = when (alarmBean.alarmType) {
                1 -> {
                    "${resources.getString(R.string.alarm_type_tamper)}${resources.getString(R.string.alarm_title)}"
                }

                2 -> {
                    "${resources.getString(R.string.function_move_detection)}${resources.getString(R.string.alarm_title)}"
                }

                else -> {
                    alarmBean.alarmDesc
                }
            }
            // 取消推送的来电通知
            val service = Intent(this, MessageIntentService::class.java).apply {
                action = Base_Constant.ACTION_CUSTOM_BACKGROUD_ALARM_NOTIFICATION
                putExtra("alarm_title", alarmTitle)
                putExtra("alarm_desc", alarmBean.devName)
            }
            startService(service)
            if (Settings.canDrawOverlays(this)) {
                Module_Record_GlobalPopoverActivityNL.startSelf(
                    this,
                    alarmBean,
                    fromRecord = alarmNotifyBean.fromRecord
                )
            }
            return
        }

        Module_Record_GlobalPopoverActivityNL.startSelf(this, alarmBean, fromRecord = alarmNotifyBean.fromRecord)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onAlarmHandleNotifyEvent(event: MessageEvent) {
        if (event.msgType == TYPE_APP_MQTT_NOTIFY_ALARM_NOTIFY) {
            val alarmNotifyHandleBean = event.msgContent as AlarmNotifyHandleBean?
            NLog.e("[jake] => [GlobalPopoverActivity] 收到信息 :  TYPE_APP_MQTT_NOTIFY_ALARM_NOTIFY....$alarmNotifyHandleBean")
            alarmNotifyHandleBean?.let { handleBean ->
                var alarmId = handleBean.data.id
                if (alarmNorifySet.contains(alarmId)) {
                    alarmNorifySet.remove(alarmId)
                } else {
                    var alarmBean = AlarmNotifyBean.Data(
                        alarmId,
                        handleBean.data.mac,
                        handleBean.data.devName,
                        handleBean.data.sip,
                        handleBean.data.alarmType,
                        handleBean.data.alarmDesc,
                        handleBean.data.alarmTime,
                        handleBean.data.handle,
                        handleBean.data.alarmIndex
                    )
                    Module_Record_GlobalPopoverActivityNL.startSelf(this, alarmBean)
                }
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onAlarmHandleCancelEvent(event: MessageEvent) {
        if (event.msgType == TYPE_POPOVER_CANCEL_ALARM_NOTIFY) {
            var alarmId = event.msgContent as Long?
            if (alarmId != null && alarmNorifySet.contains(alarmId)) {
                alarmNorifySet.remove(alarmId)
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public fun onEnterEdit(event: EnterEditEvent) {
        mBinding.mainNavigation.root.visibility = View.GONE
    }

//    @Subscribe(threadMode = ThreadMode.MAIN)
//    public fun onExitEdit(event: ExitEditEvent) {
//        mBinding.bottomNavigation.visibility = View.VISIBLE
//    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public fun onCaptureExitEditEvent(event: CaptureExitEditEvent) {
        mBinding.mainNavigation.root.visibility = View.VISIBLE
    }

    public fun onOpenDoorTimeout(msgId: String) {
        logDebug<NL_MainActivityNL>("MainActivity :  mqtt 发送 $msgId 超时")
    }

    /**
     * 执行强制退出操作
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onForcedExitEvent(event: ForcedExitEvent) {
        logDebug<NL_MainActivityNL>("[MainActivity]  收到退出: onForcedExitEvent")
        if (!event.value) {
            return
        }
        // Http logout :  token has been timeout , so not needed
        Log.e(
            TAG,
            "[MainActivity]  操作 MqttV5Service from ${javaClass.simpleName} <onForcedExitEvent> "
        )
        // Stop Mqtt
        Intent(this@NL_MainActivityNL, MqttV5Service::class.java).apply {
            action = COMMAND_DISCONNECT_MQTT
            stopService(this)
        }
        isLogin = false
        // Jump to Login
        ARouter.getInstance().build(Base_RouterPath.PATH_LOGIN)
            .withFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
            .navigation()
        // finish self
        finish()
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onExitByHttpEvent(event: ExitByHttpEvent) {
        logInfo<NL_MainActivityNL>("[MainActivity]  收到退出: onExitByHttpEvent")
        // Http logout :  token has been timeout , so not needed
        ConnectionController.getInstance(applicationContext).destroy()
        setReceivePush(false)
        mPresenter?.logout(accessToken, event.value)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onRecordReadCountActionEvent(event: RecordReadCountActionEvent) {
        Log.e(TAG, "[MainActivity].. 已读消息 : body is $event")
        mRecordReadCountActionEvent = event
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onReadCountActionEvent(event: ReadCountActionEvent) {
        Log.e(TAG, "[MainActivity].. 已读消息 : body is $event")
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 1005 || requestCode == 1006) {
            if (RomUtils.isBackgroundStartAllowed(this@NL_MainActivityNL)) {
                ToastUtils.showTextToast(getString(R.string.get_permission_success))
            } else {
                ToastUtils.showTextToast(getString(R.string.get_permission_failed))
            }
            startFvlServices()
        }
    }

    private fun showUpdateDialog(updateInfo: VersionBean) {
        Module_UserInfo_UpdateDialog.Builder(this)
            .setVersionName(updateInfo.versionName)
            .setForceUpdate(updateInfo.forceUpdate)
            .setUpdateLog(updateInfo.changeLog)
            .setButtonListener(object : Module_UserInfo_UpdateDialog.OnButtonListener {
                override fun onCloseClick() {
                    if (updateInfo.forceUpdate) {
                        this@NL_MainActivityNL.finish()
                    }
                }

                override fun onUpdateClick() {
                    updateApp()
                }
            })
            .show()
    }

    private fun jumpToFirstSetPassword() {
        startActivity(
            Intent(this, Module_Login_ForgetPwdActivityNL::class.java).apply {
                putExtra("jumpFromRegister", true)
            }
        )
    }

    private fun updateApp() {
        val appPackageName = packageName // Get the package name of the current app
        try {
            startActivity(
                Intent(
                    Intent.ACTION_VIEW,
                    "market://details?id=$appPackageName".toUri()
                )
            )
        } catch (e: android.content.ActivityNotFoundException) {
            startActivity(
                Intent(
                    Intent.ACTION_VIEW,
                    "https://play.google.com/store/apps/details?id=$appPackageName".toUri()
                )
            )
        }
    }
}
